home *** CD-ROM | disk | FTP | other *** search
/ 5 Star Games: DOS Edition 2 / 5 Star Games - DOS Edition (1995)(Ready to Run).iso / dbc / db_tree.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-05  |  41.4 KB  |  1,710 lines

  1. /****************************************************************************/
  2. /*                         DATABOSS MODULE: DB_TREE.C                       */
  3. /****************************************************************************/
  4.  
  5. #include "db_lsc.h"
  6.  
  7. #include <dos.h>
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <share.h>
  11. #include <io.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <time.h>
  16. #ifdef __TURBOC__
  17.     #include <conio.h>
  18. #else
  19.     #include <graph.h>
  20.     #include <sys\types.h>
  21. #endif
  22. #include <sys\stat.h>
  23. #include "db_types.h"
  24. #include "db_conio.h"
  25. #include "db_dos.h"
  26. #include "db_heap.h"
  27. #include "db_key.h"
  28. #include "db_tree.h"
  29.  
  30. /**********************  GLOBAL INITIALIZED VARIABLES  **********************/
  31.  
  32. bool ignoresizediff = False;
  33. bool multiuser      = False;
  34. bool flush_df       = False;
  35. bool flush_if       = False;
  36.  
  37. int createaccess    = 0x00;
  38. int openaccess      = 0x02;
  39. int shareopenaccess = 0x42;
  40.  
  41. /****************************  GLOBAL VARIABLES  ****************************/
  42.  
  43. byte errstatus;
  44. word btstatus;
  45. bool ok;
  46. bool lockget;
  47. btrecordbufptr btrecbuf;
  48. btpagestackptr btpagestk;
  49. btpagemapptr btpgmap;
  50. backdoor shutdown;
  51. bool recursive;
  52. int retries;
  53. int idx_retries;
  54. int _loop_count;
  55.  
  56. /***************************  INTERNAL VARIABLES  ***************************/
  57.  
  58. static indexfile *dk_idxf;     /* db_deletekey local global variables */
  59. static long *dk_datarecnum;
  60. static void *dk_prockey;
  61. static bool dk_pagetoosmall;
  62.  
  63. static indexfile *ak_idxf;     /* db_addkey local global variables */
  64. static long *ak_datarecnum;
  65. static void *ak_prockey;
  66. static bool ak_passup;
  67. static btitem ak_procitem1,ak_procitem2;
  68. static btpageptr ak_pageptr1,ak_pageptr2;
  69. static int ak_c,ak_k,ak_l;
  70. static long ak_prpgref2;
  71.  
  72. static bool initialized = False;
  73.  
  74. /*************************  LOW LEVEL FILE FUNCTIONS ************************/
  75. int desiredhandle = 21;  /* try to bypass 1st 20 handles */
  76.  
  77. int DB_forcedup(int current, int desired)
  78. {
  79.    int returnval;
  80.     union REGS regs;
  81.  
  82.    returnval = -1;
  83.    regs.h.ah = 0x46;
  84.    regs.x.bx = current;
  85.    regs.x.cx = desired;
  86.     intdos(®s,®s);
  87.     if (regs.x.cflag)
  88.         errno = regs.x.ax;
  89.     else
  90.       returnval = regs.x.ax;
  91.    return(returnval);
  92. }
  93.  
  94. int DB_close(int handle)
  95. {
  96.    int returnval;
  97.     union REGS regs;
  98.  
  99.    returnval = -1;
  100.    regs.h.ah = 0x3E;
  101.    regs.x.bx = handle;
  102.     intdos(®s,®s);
  103.     if (regs.x.cflag)
  104.         errno = regs.x.ax;
  105.     else
  106.       returnval = 0;
  107.    return(returnval);
  108. }
  109.  
  110. int DB_pushabove20(int handle)
  111. {
  112.   int returnval;
  113.  
  114.   returnval = handle;
  115.   if ((returnval > 0) && (returnval < 20)) {
  116.     returnval = DB_forcedup(handle,desiredhandle);
  117.     if (returnval != -1) {
  118.       DB_close(handle);
  119.       desiredhandle++;
  120.     }
  121.     else returnval = handle;
  122.   }
  123.   return(returnval);
  124. }
  125.  
  126. int DB_creat(strptr fname, int attrib)
  127. {
  128.    int returnval;
  129.     union REGS regs;
  130.    struct SREGS sregs;
  131.  
  132.    returnval = -1;
  133.    regs.h.ah = 0x3C;
  134.    sregs.ds = FP_SEG(fname);
  135.    regs.x.dx = FP_OFF(fname);
  136.    regs.x.cx = attrib;
  137.     intdosx(®s,®s,&sregs);
  138.     if (regs.x.cflag)
  139.         errno = regs.x.ax;
  140.     else
  141.       returnval = DB_pushabove20(regs.x.ax);
  142.    return(returnval);
  143. }
  144.  
  145. int DB_dup(int handle)
  146. {
  147.    int returnval;
  148.     union REGS regs;
  149.  
  150.    returnval = -1;
  151.    regs.h.ah = 0x45;
  152.    regs.x.bx = handle;
  153.     intdos(®s,®s);
  154.     if (regs.x.cflag)
  155.         errno = regs.x.ax;
  156.     else
  157.       returnval = regs.x.ax;
  158.    return(returnval);
  159. }
  160.  
  161. long DB_lseek(int handle, long offset, int fromwhere)
  162. {
  163.    long returnval;
  164.     union REGS regs;
  165.    splitlong distance;
  166.  
  167.    returnval = -1L;
  168.    regs.h.ah = 0x42;
  169.    regs.h.al = fromwhere;
  170.     distance.l = offset;
  171.     regs.x.cx = distance.w.h;
  172.     regs.x.dx = distance.w.l;
  173.    regs.x.bx = handle;
  174.     intdos(®s,®s);
  175.     if (regs.x.cflag)
  176.         errno = regs.x.ax;
  177.     else {
  178.       distance.w.h = regs.x.dx;
  179.       distance.w.l = regs.x.ax;
  180.       returnval = distance.l;
  181.    }
  182.    return(returnval);
  183. }
  184.  
  185. long DB_filelength(int handle)
  186. {
  187.    long returnval, curposn;
  188.  
  189.    returnval = -1L;
  190.    curposn = DB_lseek(handle, 0L, SEEK_CUR);
  191.    if (curposn != -1L) {
  192.      returnval = DB_lseek(handle, 0L, SEEK_END);
  193.      if (returnval != -1L) curposn = DB_lseek(handle, curposn, SEEK_SET);
  194.    }
  195.    return(returnval);
  196. }
  197.  
  198. int DB_open(strptr fname, int oflags)
  199. {
  200.    int returnval;
  201.     union REGS regs;
  202.    struct SREGS sregs;
  203.  
  204.    returnval = -1;
  205.    regs.h.ah = 0x3D;
  206.    sregs.ds = FP_SEG(fname);
  207.    regs.x.dx = FP_OFF(fname);
  208.    regs.h.al = oflags;
  209.     intdosx(®s,®s,&sregs);
  210.     if (regs.x.cflag)
  211.         errno = regs.x.ax;
  212.     else
  213.       returnval = DB_pushabove20(regs.x.ax);
  214.    return(returnval);
  215. }
  216.  
  217. int DB_read(int handle, void *buf, unsigned len)
  218. {
  219.    int returnval;
  220.     union REGS regs;
  221.    struct SREGS sregs;
  222.  
  223.    returnval = -1;
  224.    regs.h.ah = 0x3F;
  225.    sregs.ds = FP_SEG(buf);
  226.    regs.x.dx = FP_OFF(buf);
  227.    regs.x.cx = len;
  228.    regs.x.bx = handle;
  229.     intdosx(®s,®s,&sregs);
  230.     if (regs.x.cflag)
  231.         errno = regs.x.ax;
  232.     else
  233.       returnval = regs.x.ax;
  234.    return(returnval);
  235. }
  236.  
  237. int DB_write(int handle, void *buf, unsigned len)
  238. {
  239.    int returnval;
  240.     union REGS regs;
  241.    struct SREGS sregs;
  242.  
  243.    returnval = -1;
  244.    regs.h.ah = 0x40;
  245.    sregs.ds = FP_SEG(buf);
  246.    regs.x.dx = FP_OFF(buf);
  247.    regs.x.cx = len;
  248.    regs.x.bx = handle;
  249.     intdosx(®s,®s,&sregs);
  250.     if (regs.x.cflag)
  251.         errno = regs.x.ax;
  252.     else
  253.       returnval = regs.x.ax;
  254. /*************************** DISK FULL ERROR ?? ****************************
  255.    Disk IO errors are trapped by the calling routines ie. "putrec".
  256.    Disk Full is indicated by a return value less than "len" when it is not
  257.    returning an error condition of "-1".
  258.  
  259.    if ((returnval != -1) && (returnval != len)) {
  260.       returnval = -1;
  261.       errno = 101;
  262.    }
  263. ***************************************************************************/
  264.    return(returnval);
  265. }
  266. /*
  267. int DB_close(int handle) {return (_close(handle));}
  268. int DB_creat(strptr fname, int attrib) {return (_creat(fname,attrib));}
  269. int DB_dup(int handle) {return(dup(handle));}
  270. long DB_lseek(int handle, long offset, int fromwhere) {return(lseek(handle,offset,fromwhere));}
  271. long DB_filelength(int handle) {return(filelength(handle));}
  272. int DB_open(strptr fname, int oflags) {return(_open(fname,oflags));}
  273. int DB_read(int handle, void *buf, unsigned len) {return(read(handle,buf,len));}
  274. int DB_write(int handle, void *buf, unsigned len) {return(write(handle,buf,len));}
  275. */
  276.  
  277. /*****************************  IMPLEMENTATION  *****************************/
  278.  
  279. strptr ioerrstr(strptr sout, int n)
  280. {
  281.     strptr m;
  282.  
  283.     switch (n) {
  284.         case 1    : m = "Invalid DOS function code"; break;
  285.         case 2    : m = "File not found"; break;
  286.         case 3    : m = "Path not found"; break;
  287.         case 4    : m = "Too many open files"; break;
  288.         case 5    : m = "File access denied"; break;
  289.         case 6    : m = "Invalid file handle"; break;
  290.         case 8    : m = "Not enough memory"; break;
  291.         case 12   : m = "Invalid file access code"; break;
  292.         case 15   : m = "Invalid drive number"; break;
  293.         case 16   : m = "Cannot remove current directory"; break;
  294.         case 17   : m = "Cannot rename across drives"; break;
  295.         case 100  : m = "Disk read error"; break;
  296.         case 101  : m = "Disk write error"; break;
  297.         case 102  : m = "File not assigned"; break;
  298.         case 103  : m = "File not open"; break;
  299.         case 104  : m = "File not open for input"; break;
  300.         case 105  : m = "File not open for output"; break;
  301.         case 106  : m = "Invalid numeric format"; break;
  302.         case 200  : m = "Division by zero"; break;
  303.         case 201  : m = "Range check error"; break;
  304.         case 202  : m = "Stack overflow error"; break;
  305.         case 203  : m = "Heap overflow error"; break;
  306.         case 204  : m = "Invalid pointer operation"; break;
  307.         case 1000 : m = "Record size is greater than max record size"; break;
  308.         case 1001 : m = "Record size is too small"; break;
  309.         case 1002 : m = "Key length is greater than max key length"; break;
  310.         case 1003 : m = "Data File created with different record size"; break;
  311.         case 1004 : m = "Index File created with different key or page size"; break;
  312.         case 1005 : m = "Not enough memory for page stack"; break;
  313.         case 2000 : m = "Illegal attempt to alter STATUS record";
  314.         default   : m = "UnRecognized"; break;
  315.     }
  316.     return (strcpy(sout,m));
  317. }
  318.  
  319. bool outputerror(strptr filenm, long r)
  320. {
  321.     int errorfile;
  322.     errorstring emsg;
  323.     time_t t;
  324.  
  325.     errorfile = _creat(ErrFileNm,createaccess);
  326.     if (errorfile == -1) return (False);
  327.     _close(errorfile);
  328.     errorfile = open(ErrFileNm,O_TEXT | O_RDWR, S_IREAD | S_IWRITE);
  329.     if (errorfile == -1) return (False);
  330.     t = time(NULL);
  331.     sprintf(emsg,"Database I/O Fatal Error generated at %s\r\n",ctime(&t));
  332.     write(errorfile,emsg,strlen(emsg));
  333.     sprintf(emsg,"Error %d %s\r\n\r\n",btstatus,ioerrstr(emsg,btstatus));
  334.     write(errorfile,emsg,strlen(emsg));
  335.     if (*filenm) {
  336.         sprintf(emsg,"File: %s\r\nRecord: %ld\r\n",filenm,r);
  337.         write(errorfile,emsg,strlen(emsg));
  338.     }
  339.     _close(errorfile);
  340.     return (True);
  341. }
  342.  
  343. void btcrash(strptr filenm, long r)
  344. {
  345.     if (!((btstatus == 100) && multiuser)) {
  346.         if (outputerror(filenm,r)) {
  347.         }
  348.     }
  349.     errstatus = (byte) btstatus;
  350. }
  351.  
  352. void btiocheck(datafile *datf, long r)
  353. {
  354.     filename filenm;
  355.  
  356.     if (errstatus > 0) return;
  357.     if (btstatus != 0) {
  358.         strcpy(filenm,datf -> f.name);
  359.         btcrash(filenm,r);
  360.     }
  361. }
  362.  
  363. word duphandle(word handle)
  364. {
  365.     int h;
  366.  
  367.     h = DB_dup(handle);
  368.     if (h < 0) btstatus = errno;
  369.     return (h);
  370. }
  371.  
  372. void db_closefilehandle(word handle)
  373. {
  374.     if (DB_close(handle) != 0) getch();
  375.     printf("Handle = %i   Errno = %i",handle,errno);
  376. }
  377.  
  378. void flushdosfile(word handle)
  379. {
  380.     word clonehandle;
  381.  
  382.     if (errstatus > 0) return;
  383.     clonehandle = duphandle(handle);
  384.   if (btstatus == 0) DB_close(clonehandle);
  385. }
  386.  
  387. void db_getlockedrec(datafile *datf, long r, void *buffer)
  388. {
  389.     long *lbuffer;
  390.     long fpos;
  391.  
  392.     if (errstatus > 0) return;
  393.     lbuffer = buffer;
  394.     *lbuffer++ = -100;
  395.     fpos = (r * datf->itemsize) + 4;
  396.     btstatus = (DB_lseek(datf->f.handle,fpos,SEEK_SET) == -1) ? errno : 0;
  397.     if (btstatus != 0)
  398.         btstatus = (DB_lseek(datf->f.handle,fpos,SEEK_SET) == -1) ? errno : 0;
  399.     btiocheck(datf,r);
  400.     if (errstatus > 0) return;
  401.     DB_read(datf->f.handle,(void *)lbuffer,(word) datf->itemsize-4);
  402.     btiocheck(datf,r);
  403.     lockget = True;
  404. }
  405.  
  406. void db_getrec(datafile *datf, long r, void *buffer)
  407. {
  408.     word bytesread;
  409.  
  410.     if (errstatus > 0) return;
  411.     btstatus = (DB_lseek(datf->f.handle,r*datf->f.recsize,SEEK_SET) == -1) ? errno : 0;
  412.     if (btstatus != 0)
  413.             btstatus = (DB_lseek(datf->f.handle,r*datf->f.recsize,SEEK_SET)==-1) ? errno : 0;
  414.     if (multiuser && (btstatus != 0)) btstatus = 100;
  415.     btiocheck(datf,r);
  416.     if (errstatus > 0) return;
  417.     bytesread = DB_read(datf->f.handle,buffer,datf->f.recsize);
  418.     if (bytesread != datf->f.recsize) btstatus = 100;
  419.     btiocheck(datf,r);
  420. }
  421.  
  422. void db_putrec(datafile *datf, long r, void *buffer)
  423. {
  424.     word byteswritten;
  425.  
  426.     if (errstatus > 0) return;
  427.     btstatus = (DB_lseek(datf->f.handle,r*datf->f.recsize,SEEK_SET) == -1) ? errno : 0;
  428.     if (btstatus != 0)
  429.         btstatus = (DB_lseek(datf->f.handle,r*datf->f.recsize,SEEK_SET)==-1) ? errno : 0;
  430.     if (multiuser && (btstatus != 0)) btstatus = 100;
  431.     btiocheck(datf,r);
  432.     if (errstatus > 0) return;
  433.     byteswritten = DB_write(datf->f.handle,buffer,datf->f.recsize);
  434.     if (byteswritten != datf->f.recsize) btstatus = 101;
  435.     btiocheck(datf,r);
  436. }
  437.  
  438. void readheader(datafile *datf)
  439. {
  440.     if (errstatus > 0) return;
  441.     db_getrec(datf,0L,btrecbuf);
  442.     if (errstatus > 0) return;
  443.     memmove(&datf->firstfree,btrecbuf,DB_fhs);
  444.     datf->numrec = DB_filelength(datf->f.handle)/datf->f.recsize;
  445. }
  446.  
  447. bool vfydtahdr(datafile *datf)
  448. {
  449.     if (multiuser && (errstatus == 0)) readheader(datf);
  450.     return ((bool) (errstatus == 0));
  451. }
  452.  
  453. bool vfyidxhdr(indexfile *idxf)
  454. {
  455.     if (multiuser && (errstatus == 0)) {
  456.         readheader(&idxf->dataf);
  457.         idxf->rr = idxf->dataf.int1;
  458.     }
  459.     return ((bool) (errstatus == 0));
  460. }
  461.  
  462. void writeheader(datafile *datf, word reclen)
  463. {
  464.     if (errstatus > 0) return;
  465.     memset(btrecbuf,0,sizeof(*btrecbuf));
  466.     datf->firstfree = -1;
  467.     datf->itemsize = reclen;
  468.     memmove(btrecbuf,&datf->firstfree,DB_fhs);
  469.     db_putrec(datf,0L,btrecbuf);
  470.     btiocheck(datf,0L);
  471.     if (errstatus > 0) return;
  472.     datf->numrec = 1;
  473.     ok = True;
  474. }
  475.  
  476. void db_makefile(datafile *datf, strptr fname, word reclen)
  477. {
  478.     if (errstatus > 0) return;
  479.     btstatus = 0;
  480.     memset(datf,0,sizeof(*datf));
  481.     datf->f.handle = DB_creat(fname,createaccess);
  482.     datf->f.recsize = reclen;
  483.     strcpy(datf->f.name,fname);
  484.     ok = (bool) (datf->f.handle != -1);
  485.     if (ok) {
  486.         if (reclen > DB_mxdrs) btstatus = RecTooLarge;
  487.         if (reclen < DB_mdrs) btstatus = RecTooSmall;
  488.         btiocheck(datf,0L);
  489.         writeheader(datf,reclen);
  490.         if (errstatus > 0) return;
  491.     }
  492. }
  493.  
  494. void db_openfile(datafile *datf, strptr fname, word reclen)
  495. {
  496.     if (errstatus > 0) return;
  497.     memset(datf,0,sizeof(*datf));
  498.     if (multiuser)
  499.         datf->f.handle = DB_open(fname, shareopenaccess);
  500.     else
  501.         datf->f.handle = DB_open(fname,openaccess);
  502.     datf->f.recsize = reclen;
  503.     strcpy(datf->f.name,fname);
  504.     btstatus = (datf->f.handle != -1) ? 0 : errno;
  505.     ok = (bool) (btstatus == 0);
  506.     if (ok) {
  507.         if (reclen > DB_mxdrs) btstatus = RecTooLarge;
  508.         if (reclen < DB_mdrs) btstatus = RecTooSmall;
  509.         btiocheck(datf,0L);
  510.         readheader(datf);
  511.         if (errstatus > 0) return;
  512.         if (reclen != (word) datf->itemsize) {
  513.             if (ignoresizediff)
  514.                 datf->itemsize = reclen;
  515.             else {
  516.                 btstatus = RecSizeMismatch;
  517.                 btiocheck(datf,0L);
  518.             }
  519.         }
  520.     }
  521. }
  522.  
  523. void putfileheader(datafile *datf)
  524. {
  525.     if (errstatus > 0) return;
  526.     memset(btrecbuf,0,sizeof(*btrecbuf));
  527.     datf->int2 = datf->numrec;
  528.     datf->itemsize = datf->f.recsize;
  529.     memmove(btrecbuf,&datf->firstfree,DB_fhs);
  530.     db_putrec(datf,0L,btrecbuf);
  531. }
  532.  
  533. void db_closefile(datafile *datf)
  534. {
  535.     if (!vfydtahdr(datf)) return;
  536.     putfileheader(datf);
  537.     if (errstatus > 0) return;
  538.     btstatus = (DB_close(datf->f.handle) == 0) ? 0 : errno;
  539.     btiocheck(datf,0L);
  540. }
  541.  
  542. void db_flushfile(datafile *datf)
  543. {
  544.     if (!vfydtahdr(datf)) return;
  545.     putfileheader(datf);
  546.     flushdosfile(datf->f.handle);
  547.     btiocheck(datf,0L);
  548. }
  549.  
  550. void newrec(datafile *datf, long *r)
  551. {
  552.     if (errstatus > 0) return;
  553.     if (datf->firstfree == -1)
  554.         *r = datf->numrec++;
  555.     else {
  556.         *r = datf->firstfree;
  557.         db_getrec(datf,*r,btrecbuf);
  558.         if (errstatus > 0) return;
  559.         datf->firstfree = btrecbuf->i;
  560.         datf->numberfree--;
  561.     }
  562. }
  563.  
  564. void db_addrec(datafile *datf, long *r, void *buffer)
  565. {
  566.     if (!vfydtahdr(datf)) return;
  567.     newrec(datf,r);
  568.     db_putrec(datf,*r,buffer);
  569.     if (errstatus > 0) return;
  570.     if (multiuser) putfileheader(datf);
  571. }
  572.  
  573. void db_deleterec(datafile *datf, long r)
  574. {
  575.     if (!vfydtahdr(datf)) return;
  576.     btrecbuf->i = datf->firstfree;
  577.     db_putrec(datf,r,btrecbuf);
  578.     if (errstatus > 0) return;
  579.     datf->firstfree = r;
  580.     datf->numberfree++;
  581.     if (multiuser) putfileheader(datf);
  582. }
  583.  
  584. long db_filelen(datafile *datf)
  585. {
  586.     return ((vfydtahdr(datf)) ? datf->numrec : 0);
  587. }
  588.  
  589. long db_usedrecs(datafile *datf)
  590. {
  591.     return ((vfydtahdr(datf)) ? datf->numrec - datf->numberfree - 1 : 0);
  592. }
  593.  
  594. void db_initindex(void)
  595. /* done by unit initialization they reckon */
  596. {
  597. }
  598.  
  599. void btpack(btpage *page, byte keyl)
  600. {
  601.     byteptr p;
  602.     int isize;
  603.     int i;
  604.  
  605.     if (keyl != DB_Klen) {
  606.         p = ((byteptr) page) + PageOverhead;
  607.         isize = keyl + ItemOverhead;
  608.         for (i = 0; i < DB_ps ; i++)
  609.             memmove(p+(i*isize),&page->itemarray[i],isize);
  610.     }
  611. }
  612.  
  613. void btunpack(btpage *page, byte keyl)
  614. {
  615.     byteptr p;
  616.     int isize;
  617.     int i;
  618.  
  619.     if (keyl != DB_Klen) {
  620.         p = ((byteptr) page) + PageOverhead;
  621.         isize = keyl + ItemOverhead;
  622.         for (i = DB_ps-1 ; i >= 0 ; i--)
  623.             memmove(&page->itemarray[i],p+(i*isize),isize);
  624.     }
  625. }
  626.  
  627. void db_makeindex(indexfile *idxf, strptr fname, byte keylen, byte s)
  628. {
  629.     word k;
  630.  
  631.     if (errstatus > 0) return;
  632.     memset(idxf,0,sizeof(*idxf));
  633.     k = (keylen + ItemOverhead) * DB_ps + PageOverhead;
  634.     idxf->dataf.f.handle = DB_creat(fname,createaccess);
  635.     idxf->dataf.f.recsize = k;
  636.     strcpy(idxf->dataf.f.name,fname);
  637.     btstatus = (idxf->dataf.f.handle != -1) ? 0 : errno;
  638.     if (keylen > DB_Klen)
  639.         btstatus = KeyTooLarge;
  640.     btiocheck(&idxf->dataf,0L);
  641.     writeheader(&idxf->dataf,k);
  642.     if (errstatus > 0)
  643.         return;
  644.     idxf->allowduplkeys = (bool) (s != NoDuplicates);
  645.     idxf->keyl = keylen;
  646. }
  647.  
  648. void db_openindex(indexfile *idxf, strptr fname, byte keylen, byte s)
  649. {
  650.     word k;
  651.  
  652.     if (errstatus > 0) return;
  653.     memset(idxf,0,sizeof(*idxf));
  654.     k = (keylen + ItemOverhead) * DB_ps + PageOverhead;
  655.     if (multiuser)
  656.         idxf->dataf.f.handle = DB_open(fname, shareopenaccess);
  657.     else
  658.         idxf->dataf.f.handle = DB_open(fname, openaccess);
  659.     idxf->dataf.f.recsize = k;
  660.     strcpy(idxf->dataf.f.name,fname);
  661.     btstatus = (idxf->dataf.f.handle != -1) ? 0 : errno;
  662.     ok = (bool) (btstatus == 0);
  663.     if (ok) {
  664.         if (keylen > DB_Klen) {
  665.             btstatus = KeyTooLarge;
  666.             btiocheck(&idxf->dataf,0L);
  667.             if (errstatus > 0) return;
  668.         }
  669.         readheader(&idxf->dataf);
  670.         if (errstatus > 0) return;
  671.         if (k != (word) idxf->dataf.itemsize) {
  672.             if (ignoresizediff)
  673.                 idxf->dataf.itemsize = k;
  674.             else {
  675.                 btstatus = KeySizeMismatch;
  676.                 btiocheck(&idxf->dataf,0L);
  677.                 if (errstatus > 0) return;
  678.             }
  679.         }
  680.         idxf->allowduplkeys = (bool) (s != NoDuplicates);
  681.         idxf->keyl = keylen;
  682.         idxf->rr = idxf->dataf.int1;
  683.         idxf->pp = 0;
  684.     }
  685. }
  686.  
  687. void storeindexheader(indexfile *idxf)
  688. {
  689.     int i;
  690.     btstackrecptr btsrp;
  691.  
  692.     if (errstatus > 0) return;
  693.     for (i = 1, btsrp = &(*btpagestk)[0]; i <= DB_pstack; i++, btsrp++) {
  694.         if (btsrp->indexfptr == idxf) {
  695.             btsrp->indexfptr = NULL;
  696.             if (btsrp->updated) {
  697.                 btpack(&btsrp->page,idxf->keyl);
  698.                 db_putrec(&idxf->dataf,btsrp->pageref,&btsrp->page);
  699.                 if (errstatus > 0) return;
  700.                 btsrp->updated = False;
  701.             }
  702.         }
  703.     }
  704.     idxf->dataf.int1 = idxf->rr;
  705. }
  706.  
  707. void db_closeindex(indexfile *idxf)
  708. {
  709.     if (!vfyidxhdr(idxf)) return;
  710.     storeindexheader(idxf);
  711.     db_closefile(&idxf->dataf);
  712. }
  713.  
  714. void db_flushindex(indexfile *idxf)
  715. {
  716.     if (!vfyidxhdr(idxf)) return;
  717.     storeindexheader(idxf);
  718.     db_flushfile(&idxf->dataf);
  719. }
  720.  
  721. void db_erasefile(datafile *datf)
  722. {
  723.     db_closefile(datf);
  724.     if (errstatus > 0) return;
  725.     unlink(datf->f.name);
  726. }
  727.  
  728. void db_eraseindex(indexfile *idxf)
  729. {
  730.     db_closeindex(idxf);
  731.     if (errstatus > 0) return;
  732.     unlink(idxf->dataf.f.name);
  733. }
  734.  
  735. void btlast(long i)
  736. {
  737.     int j,k;
  738.  
  739.     j = 1;
  740.     while (((*btpgmap)[j-1] != (word) i) && (j < DB_pstack)) j++;
  741.     for (k = j ; k <= (DB_pstack-1) ; k++)
  742.         (*btpgmap)[k-1] = (*btpgmap)[k];
  743.     (*btpgmap)[DB_pstack-1] = (word) i;
  744. }
  745.  
  746. void btgetpage(indexfile *idxf, long r, btpageptr *pgptr)
  747. {
  748.     long i;
  749.     bool found;
  750.     btstackrecptr btsrp;
  751.  
  752.     if (errstatus > 0) return;
  753.     i = 0;
  754.     if (multiuser)
  755.         found = False;
  756.     else {
  757.         do {
  758.             i++;
  759.             btsrp = &(*btpagestk)[(int) i-1];
  760.             found = (bool) ((btsrp->indexfptr == idxf) && (btsrp->pageref == r));
  761.         } while ((!found) && (i < DB_pstack));
  762.     }
  763.     if (!found) {
  764.         i = (*btpgmap)[0];
  765.         btsrp = &(*btpagestk)[(int) i-1];
  766.         if (btsrp->updated) {
  767.             btpack(&btsrp->page,btsrp->indexfptr->keyl);
  768.             db_putrec(&btsrp->indexfptr->dataf,btsrp->pageref,&btsrp->page);
  769.             if (errstatus > 0) return;
  770.         }
  771.         db_getrec(&idxf->dataf,r,&btsrp->page);
  772.         if (errstatus > 0) return;
  773.         btunpack(&btsrp->page,idxf->keyl);
  774.         btsrp->indexfptr = idxf;
  775.         btsrp->pageref = r;
  776.         btsrp->updated = False;
  777.     }
  778.     btlast(i);
  779.     *pgptr = &(*btpagestk)[(int) i-1].page;
  780. }
  781.  
  782. void btnewpage(indexfile *idxf, long *r, btpageptr *pgptr)
  783. {
  784.     long i;
  785.     btstackrecptr btsrp;
  786.  
  787.     if (errstatus > 0) return;
  788.     i = (*btpgmap)[0];
  789.     btsrp = &(*btpagestk)[(int) i-1];
  790.     if (btsrp->updated) {
  791.         btpack(&btsrp->page,btsrp->indexfptr->keyl);
  792.         db_putrec(&btsrp->indexfptr->dataf,btsrp->pageref,&btsrp->page);
  793.         if (errstatus > 0) return;
  794.     }
  795.     newrec(&idxf->dataf,r);
  796.     if (errstatus > 0) return;
  797.     btsrp->indexfptr = idxf;
  798.     btsrp->pageref = *r;
  799.     btsrp->updated = False;
  800.     btlast(i);
  801.     *pgptr = &(*btpagestk)[(int) i-1].page;
  802. }
  803.  
  804. void btupdatepage(btpageptr pgptr)
  805. {
  806.     btstackrecptr btsrp;
  807.  
  808.     if (errstatus > 0) return;
  809.     btsrp = (btstackrecptr) pgptr;
  810.     if (multiuser) {
  811.         btpack(&btsrp->page,btsrp->indexfptr->keyl);
  812.         db_putrec(&btsrp->indexfptr->dataf,btsrp->pageref,&btsrp->page);
  813.         if (errstatus > 0) return;
  814.         btunpack(&btsrp->page,btsrp->indexfptr->keyl);
  815.         btsrp->indexfptr->dataf.int1 = btsrp->indexfptr->rr;
  816.         putfileheader(&btsrp->indexfptr->dataf);
  817.     }
  818.     else
  819.         btsrp->updated = True;
  820. }
  821.  
  822. void btreturnpage(btpageptr *pgptr)
  823. {
  824.     btstackrecptr btsrp;
  825.  
  826.     if (errstatus > 0) return;
  827.     btsrp = (btstackrecptr) *pgptr;
  828.     db_deleterec(&btsrp->indexfptr->dataf,btsrp->pageref);
  829.     if (errstatus > 0) return;
  830.     btsrp->indexfptr->dataf.int1 = btsrp->indexfptr->rr;
  831.     putfileheader(&btsrp->indexfptr->dataf);
  832.     btsrp->indexfptr = NULL;
  833.     btsrp->updated = False;
  834. }
  835.  
  836. void btxkey(void *k, byte keyl)
  837. {
  838.     strptr s;
  839.  
  840.     s = k;
  841.     if (strlen(s) > keyl) s[keyl] = '\0';
  842. }
  843.  
  844. int btcompkeys(void *k1, void *k2, long dr1, long dr2, bool dup)
  845. {
  846.     strptr s1,s2;
  847.     int i;
  848.  
  849.     s1 = k1;
  850.     s2 = k2;
  851.     if (strcmp(s1,s2) == 0) {
  852.         if ((!dup) || (dr1 == dr2))
  853.             i = 0;
  854.         else
  855.             i = ((dr1+0x80000000L) > (dr2+0x80000000L)) ? 1 : -1;
  856.     }
  857.     else
  858.         i = (strcmp(s1,s2) > 0) ? 1 : -1;
  859.     return (i);
  860. }
  861.  
  862. void db_clearkey(indexfile *idxf)
  863. {
  864.     if (errstatus > 0) return;
  865.     idxf->pp = 0;
  866. }
  867.  
  868. void db_nextkey(indexfile *idxf,long *datarecnum, void *prockey)
  869. {
  870.     long r;
  871.     btpageptr pagptr;
  872.     btsearchstepptr btssp;
  873.     btitemptr btip;
  874.  
  875.     if (!vfyidxhdr(idxf)) return;
  876.     if (idxf->pp == 0)
  877.         r = idxf->rr;
  878.     else {
  879.         btssp = &idxf->path[(int) idxf->pp-1];
  880.         btgetpage(idxf,btssp->pageref,&pagptr);
  881.         if (errstatus) return;
  882.         r = pagptr->itemarray[(int) btssp->itemarrindex-1].pageref;
  883.     }
  884.     while (r != 0) {
  885.         (idxf->pp)++;
  886.         btssp = &idxf->path[(int) idxf->pp-1];
  887.         btssp->pageref = r;
  888.         btssp->itemarrindex = 0;
  889.         btgetpage(idxf,r,&pagptr);
  890.         if (errstatus) return;
  891.         r = pagptr->bckwpageref;
  892.     }
  893.     if (idxf->pp != 0) {
  894.         btssp = &idxf->path[(int) idxf->pp-1];
  895.         while ((idxf->pp > 1) && (btssp->itemarrindex == pagptr->itemsonpage)) {
  896.             (idxf->pp)--;
  897.             btssp--;
  898.             btgetpage(idxf,btssp->pageref,&pagptr);
  899.             if (errstatus) return;
  900.         }
  901.         if (btssp->itemarrindex < pagptr->itemsonpage) {
  902.             (btssp->itemarrindex)++;
  903.             btip = &pagptr->itemarray[(int) btssp->itemarrindex-1];
  904.             strcpy(prockey,btip->key);
  905.             *datarecnum = btip->dataref;
  906.         }
  907.         else
  908.             idxf->pp = 0;
  909.     }
  910.     ok = (bool) (idxf->pp != 0);
  911. }
  912.  
  913. void db_prevkey(indexfile *idxf,long *datarecnum, void *prockey)
  914. {
  915.     long r;
  916.     btpageptr pagptr;
  917.     btsearchstepptr btssp;
  918.     btitemptr btip;
  919.  
  920.     if (!vfyidxhdr(idxf)) return;
  921.     if (idxf->pp == 0)
  922.         r = idxf->rr;
  923.     else {
  924.         btssp = &idxf->path[(int) idxf->pp-1];
  925.         btgetpage(idxf,btssp->pageref,&pagptr);
  926.         if (errstatus) return;
  927.         if (--(btssp->itemarrindex) == 0)
  928.             r = pagptr->bckwpageref;
  929.         else
  930.         r = pagptr->itemarray[(int) btssp->itemarrindex-1].pageref;
  931.     }
  932.     while (r != 0) {
  933.         btgetpage(idxf,r,&pagptr);
  934.         if (errstatus) return;
  935.         (idxf->pp)++;
  936.         btssp = &idxf->path[(int) idxf->pp-1];
  937.         btssp->pageref = r;
  938.         btssp->itemarrindex = pagptr->itemsonpage;
  939.         r = pagptr->itemarray[pagptr->itemsonpage-1].pageref;
  940.     }
  941.     if (idxf->pp != 0) {
  942.         btssp = &idxf->path[(int) idxf->pp-1];
  943.         while ((idxf->pp > 1) && (btssp->itemarrindex == 0)) {
  944.             (idxf->pp)--;
  945.             btssp--;
  946.             btgetpage(idxf,btssp->pageref,&pagptr);
  947.             if (errstatus) return;
  948.         }
  949.         if (btssp->itemarrindex > 0) {
  950.             btip = &pagptr->itemarray[(int) btssp->itemarrindex-1];
  951.             strcpy(prockey,btip->key);
  952.             *datarecnum = btip->dataref;
  953.         }
  954.         else
  955.             idxf->pp = 0;
  956.     }
  957.     ok = (bool) (idxf->pp !=0);
  958. }
  959.  
  960. void btdb_findkey(indexfile *idxf,long *datarecnum, void *prockey)
  961. {
  962.     long prpgref;
  963.     int c,k,l,r;
  964.     btpageptr pagptr;
  965.     btsearchstepptr btssp;
  966.  
  967.     if (!vfyidxhdr(idxf)) return;
  968.     btxkey(prockey,idxf->keyl);
  969.     ok = False;
  970.     idxf->pp = 0;
  971.     prpgref = idxf->rr;
  972.     while ((prpgref != 0) && !ok) {
  973.         (idxf->pp)++;
  974.         idxf->path[(int) idxf->pp-1].pageref = prpgref;
  975.         btgetpage(idxf,prpgref,&pagptr);
  976.         if (errstatus > 0) return;
  977.         l = 1;
  978.         r = pagptr->itemsonpage;
  979.         do {
  980.             k = (l + r)/2;
  981.             c = btcompkeys(prockey,pagptr->itemarray[k-1].key,0L,
  982.                     pagptr->itemarray[k-1].dataref,idxf->allowduplkeys);
  983.             if (c <= 0)    r = k - 1;
  984.             if (c >= 0) l = k + 1;
  985.         } while   (r >= l);
  986.         if (l - r > 1) {
  987.             *datarecnum = pagptr->itemarray[k-1].dataref;
  988.             r = k;
  989.             ok = True;
  990.         }
  991.         prpgref = (r==0)?pagptr->bckwpageref:pagptr->itemarray[r-1].pageref;
  992.         idxf->path[(int) idxf->pp-1].itemarrindex = r;
  993.     }
  994.     if ((!ok) && (idxf->pp > 0)) {
  995.         btssp = &idxf->path[(int) idxf->pp-1];
  996.         while ((idxf->pp > 1) && (btssp->itemarrindex == 0)) {
  997.             (idxf->pp)--;
  998.             btssp--;
  999.         }
  1000.         if (btssp->itemarrindex == 0) idxf->pp = 0;
  1001.     }
  1002. }
  1003.  
  1004. void db_findkey(indexfile *idxf,long *datarecnum, void *prockey)
  1005. {
  1006.     btkeystr tempkey;
  1007.  
  1008.     btdb_findkey(idxf,datarecnum,prockey);
  1009.     if (errstatus > 0 ) return;
  1010.     if ((!ok) && (idxf->allowduplkeys)) {
  1011.         strcpy(tempkey,prockey);
  1012.         db_nextkey(idxf,datarecnum,prockey);
  1013.         if (errstatus > 0 ) return;
  1014.         ok = (bool) (ok && (strcmp(prockey,tempkey) == 0));
  1015.     }
  1016. }
  1017.  
  1018. void db_search(indexfile *idxf,long *datarecnum, void *prockey)
  1019. {
  1020.     btdb_findkey(idxf,datarecnum,prockey);
  1021.     if (errstatus > 0 ) return;
  1022.     if (!ok) db_nextkey(idxf,datarecnum,prockey);
  1023. }
  1024.  
  1025. void ak_insert(long prpgref1, int *r)
  1026. {
  1027.     int i;
  1028.  
  1029.     btgetpage(ak_idxf,prpgref1,&ak_pageptr1);
  1030.     if (errstatus > 0) return;
  1031.     if (ak_pageptr1->itemsonpage < DB_ps) {
  1032.         (ak_pageptr1->itemsonpage)++;
  1033.         for (i = ak_pageptr1->itemsonpage ; i >= *r+2 ; i--)
  1034.             ak_pageptr1->itemarray[i-1] = ak_pageptr1->itemarray[i-2];
  1035.         ak_pageptr1->itemarray[*r] = ak_procitem1;
  1036.         ak_passup = False;
  1037.     }
  1038.     else {
  1039.         btnewpage(ak_idxf,&ak_prpgref2,&ak_pageptr2);
  1040.         if (errstatus > 0) return;
  1041.         if (*r <= DB_ord) {
  1042.             if (*r == DB_ord)
  1043.                 ak_procitem2 = ak_procitem1;
  1044.             else {
  1045.                 ak_procitem2 = ak_pageptr1->itemarray[DB_ord-1];
  1046.                 for (i = DB_ord; i >= *r + 2 ; i--)
  1047.                     ak_pageptr1->itemarray[i-1] = ak_pageptr1->itemarray[i-2];
  1048.                 ak_pageptr1->itemarray[*r] = ak_procitem1;
  1049.             }
  1050.             for (i = 1 ; i <= DB_ord ; i++)
  1051.                 ak_pageptr2->itemarray[i-1]=ak_pageptr1->itemarray[i+DB_ord-1];
  1052.         }
  1053.         else {
  1054.             *r -= DB_ord;
  1055.             ak_procitem2 = ak_pageptr1->itemarray[DB_ord];
  1056.             for (i = 1 ; i <= *r - 1 ; i++)
  1057.                 ak_pageptr2->itemarray[i-1]=ak_pageptr1->itemarray[i+DB_ord];
  1058.             ak_pageptr2->itemarray[*r-1] = ak_procitem1;
  1059.             for (i = *r + 1 ; i <= DB_ord ; i++)
  1060.                 ak_pageptr2->itemarray[i-1]=ak_pageptr1->itemarray[i+DB_ord-1];
  1061.         }
  1062.         ak_pageptr1->itemsonpage = DB_ord;
  1063.         ak_pageptr2->itemsonpage = DB_ord;
  1064.         ak_pageptr2->bckwpageref = ak_procitem2.pageref;
  1065.         ak_procitem2.pageref = ak_prpgref2;
  1066.         ak_procitem1 = ak_procitem2;
  1067.         btupdatepage(ak_pageptr2);
  1068.         if (errstatus > 0) return;
  1069.     }
  1070.     btupdatepage(ak_pageptr1);
  1071. }
  1072.  
  1073. void ak_search(long prpgref1)
  1074. {
  1075.     int r;
  1076.  
  1077.     if (errstatus > 0) return;
  1078.     if (prpgref1 == 0) {
  1079.         ak_passup = True;
  1080.         strcpy(ak_procitem1.key,ak_prockey);
  1081.         ak_procitem1.dataref = *ak_datarecnum;
  1082.         ak_procitem1.pageref = 0;
  1083.     }
  1084.     else {
  1085.         btgetpage(ak_idxf,prpgref1,&ak_pageptr1);
  1086.         if (errstatus > 0) return;
  1087.         ak_l = 1;
  1088.         r = ak_pageptr1->itemsonpage;
  1089.         do {
  1090.             ak_k = (ak_l + r)/2;
  1091.             ak_c = btcompkeys(ak_prockey,ak_pageptr1->itemarray[ak_k-1].key,
  1092.                                                 *ak_datarecnum,
  1093.                                                 ak_pageptr1->itemarray[ak_k-1].dataref,
  1094.                                                 ak_idxf->allowduplkeys);
  1095.             if (ak_c <= 0) r = ak_k - 1;
  1096.             if (ak_c >= 0) ak_l = ak_k + 1;
  1097.         } while (r >= ak_l);
  1098.         if ((ak_l-r) > 1) {
  1099.             ok = False;
  1100.             ak_passup = False;
  1101.         }
  1102.         else {
  1103.             if (r == 0)
  1104.                 ak_search(ak_pageptr1->bckwpageref);
  1105.             else
  1106.                 ak_search(ak_pageptr1->itemarray[r-1].pageref);
  1107.             if (errstatus > 0) return;
  1108.             if (ak_passup) ak_insert(prpgref1,&r);
  1109.         }
  1110.     }
  1111. }
  1112.  
  1113. void db_addkey(indexfile *idxf, long *datarecnum, void *prockey)
  1114. {
  1115.     long prpgref1;
  1116.  
  1117.     if (!vfyidxhdr(idxf)) return;
  1118.     ak_idxf = idxf;
  1119.     ak_datarecnum = datarecnum;
  1120.     ak_prockey = prockey;
  1121.     btxkey(prockey,idxf->keyl);
  1122.     ok = True;
  1123.     ak_search(idxf->rr);
  1124.     if (errstatus > 0) return;
  1125.     if (ak_passup) {
  1126.         prpgref1 = idxf->rr;
  1127.         btnewpage(idxf,&idxf->rr,&ak_pageptr1);
  1128.         if (errstatus > 0) return;
  1129.         ak_pageptr1->itemsonpage = 1;
  1130.         ak_pageptr1->bckwpageref = prpgref1;
  1131.         ak_pageptr1->itemarray[0] = ak_procitem1;
  1132.         btupdatepage(ak_pageptr1);
  1133.         if (errstatus > 0) return;
  1134.     }
  1135.     idxf->pp = 0;
  1136. }
  1137.  
  1138. void dk_underflow(long prpgref, long prpgref2, int r)
  1139. {
  1140.     int i,k,litem;
  1141.     long lpageref;
  1142.     btpageptr pagptr,pageptr2,l;
  1143.  
  1144.     btgetpage(dk_idxf,prpgref,&pagptr);
  1145.     btgetpage(dk_idxf,prpgref2,&pageptr2);
  1146.     if (errstatus > 0) return;
  1147.     if (r < pagptr->itemsonpage) {
  1148.         r++;
  1149.         lpageref = pagptr->itemarray[r-1].pageref;
  1150.         btgetpage(dk_idxf,lpageref,&l);
  1151.         if (errstatus > 0) return;
  1152.         k = (l->itemsonpage - DB_ord + 1)/2;
  1153.         pageptr2->itemarray[DB_ord-1] = pagptr->itemarray[r-1];
  1154.         pageptr2->itemarray[DB_ord-1].pageref = l->bckwpageref;
  1155.         if (k > 0) {
  1156.             for (i = 1 ; i <= k-1 ; i++)
  1157.                 pageptr2->itemarray[i+DB_ord-1] = l->itemarray[i-1];
  1158.             pagptr->itemarray[r-1] = l->itemarray[k-1];
  1159.             pagptr->itemarray[r-1].pageref = lpageref;
  1160.             l->bckwpageref = l->itemarray[k-1].pageref;
  1161.             l->itemsonpage = l->itemsonpage - k;
  1162.             for (i = 1 ; i <= l->itemsonpage ; i++)
  1163.                 l->itemarray[i-1] = l->itemarray[i+k-1];
  1164.             pageptr2->itemsonpage = (byte) (DB_ord - 1 + k);
  1165.             dk_pagetoosmall = False;
  1166.             btupdatepage(l);
  1167.             if (errstatus > 0) return;
  1168.         }
  1169.         else {
  1170.             for (i = 1 ; i <= DB_ord ; i++)
  1171.                 pageptr2->itemarray[i+DB_ord-1] = l->itemarray[i-1];
  1172.             for (i = r ; i <= pagptr->itemsonpage-1 ; i++)
  1173.                 pagptr->itemarray[i-1] = pagptr->itemarray[i];
  1174.             pageptr2->itemsonpage = DB_ps;
  1175.             pagptr->itemsonpage = pagptr->itemsonpage - 1;
  1176.             btreturnpage(&l);
  1177.             if (errstatus > 0) return;
  1178.             dk_pagetoosmall = (bool) (pagptr->itemsonpage < DB_ord);
  1179.         }
  1180.         btupdatepage(pageptr2);
  1181.         if (errstatus > 0) return;
  1182.     }
  1183.     else {
  1184.         lpageref = (r==1)?pagptr->bckwpageref:pagptr->itemarray[r-2].pageref;
  1185.         btgetpage(dk_idxf,lpageref,&l);
  1186.         if (errstatus > 0) return;
  1187.         litem = l->itemsonpage + 1;
  1188.         k = (litem - DB_ord)/2;
  1189.         if (k > 0) {
  1190.             for (i = DB_ord-1 ; i >= 1 ; i--)
  1191.                 pageptr2->itemarray[i+k-1] = pageptr2->itemarray[i-1];
  1192.             pageptr2->itemarray[k-1] = pagptr->itemarray[r-1];
  1193.             pageptr2->itemarray[k-1].pageref = pageptr2->bckwpageref;
  1194.             litem = litem - k;
  1195.             for (i = k-1 ; i >= 1 ; i--)
  1196.                 pageptr2->itemarray[i-1] = l->itemarray[i+litem-1];
  1197.             pageptr2->bckwpageref = l->itemarray[litem-1].pageref;
  1198.             pagptr->itemarray[r-1] = l->itemarray[litem-1];
  1199.             pagptr->itemarray[r-1].pageref = prpgref2;
  1200.             l->itemsonpage = (byte) (litem - 1);
  1201.             pageptr2->itemsonpage = (byte) (DB_ord - 1 + k);
  1202.             dk_pagetoosmall = False;
  1203.             btupdatepage(pageptr2);
  1204.             if (errstatus > 0) return;
  1205.         }
  1206.         else {
  1207.             l->itemarray[litem-1] = pagptr->itemarray[r-1];
  1208.             l->itemarray[litem-1].pageref = pageptr2->bckwpageref;
  1209.             for (i = 1 ; i <= DB_ord-1 ; i++)
  1210.                 l->itemarray[i+litem-1] = pageptr2->itemarray[i-1];
  1211.             l->itemsonpage = DB_ps;
  1212.             pagptr->itemsonpage = pagptr->itemsonpage - 1;
  1213.             btreturnpage(&pageptr2);
  1214.             if (errstatus > 0) return;
  1215.             dk_pagetoosmall = (bool) (pagptr->itemsonpage < DB_ord);
  1216.         }
  1217.         btupdatepage(l);
  1218.         if (errstatus > 0) return;
  1219.     }
  1220.     btupdatepage(pagptr);
  1221. }
  1222.  
  1223. void dk_dela(long prpgref2,long k, btpageptr *pagptr, long *prpgref)
  1224. {
  1225.     int c;
  1226.     long xpageref;
  1227.     btpageptr pageptr2;
  1228.  
  1229.     btgetpage(dk_idxf,prpgref2,&pageptr2);
  1230.     if (errstatus > 0) return;
  1231.     xpageref = pageptr2->itemarray[pageptr2->itemsonpage-1].pageref;
  1232.     if (xpageref != 0) {
  1233.         c = pageptr2->itemsonpage;
  1234.         dk_dela(xpageref,k,pagptr,prpgref);
  1235.         if (dk_pagetoosmall)
  1236.             dk_underflow(prpgref2,xpageref,c);
  1237.         if (errstatus > 0) return;
  1238.     }
  1239.     else {
  1240.         btgetpage(dk_idxf,*prpgref,pagptr);
  1241.         if (errstatus > 0) return;
  1242.         pageptr2->itemarray[pageptr2->itemsonpage-1].pageref =
  1243.                     (*pagptr)->itemarray[(int) k-1].pageref;
  1244.         (*pagptr)->itemarray[(int) k-1] =
  1245.                     pageptr2->itemarray[pageptr2->itemsonpage-1];
  1246.         (pageptr2->itemsonpage)--;
  1247.         dk_pagetoosmall = (bool) (pageptr2->itemsonpage < DB_ord);
  1248.         btupdatepage(*pagptr);
  1249.         btupdatepage(pageptr2);
  1250.         if (errstatus > 0) return;
  1251.     }
  1252. }
  1253.  
  1254. void dk_delb(long prpgref)
  1255. {
  1256.     long c,i,k,l,r,xpageref;
  1257.     btpageptr pagptr;
  1258.  
  1259.     if (errstatus > 0) return;
  1260.     if (prpgref == 0) {
  1261.         ok = False;
  1262.         dk_pagetoosmall = False;
  1263.     }
  1264.     else {
  1265.         btgetpage(dk_idxf,prpgref,&pagptr);
  1266.         if (errstatus > 0) return;
  1267.         l = 1;
  1268.         r = pagptr->itemsonpage;
  1269.         do {
  1270.             k = (l + r)/2;
  1271.             c = btcompkeys(dk_prockey,pagptr->itemarray[(int) k-1].key,
  1272.                                         *dk_datarecnum,
  1273.                                         pagptr->itemarray[(int) k-1].dataref,
  1274.                                         dk_idxf->allowduplkeys);
  1275.             if (c <= 0) r = k - 1;
  1276.             if (c >= 0) l = k + 1;
  1277.         } while (l <= r);
  1278.         xpageref = (r == 0) ? pagptr->bckwpageref : pagptr->itemarray[(int) r-1].pageref;
  1279.         if (l - r > 1) {
  1280.             *dk_datarecnum = pagptr->itemarray[(int) k-1].dataref;
  1281.             if (xpageref == 0) {
  1282.                 pagptr->itemsonpage = pagptr->itemsonpage - 1;
  1283.                 dk_pagetoosmall = (bool) (pagptr->itemsonpage < DB_ord);
  1284.                 for (i=k ; i <= pagptr->itemsonpage ; i++)
  1285.                     pagptr->itemarray[(int) i-1]=pagptr->itemarray[(int) i];
  1286.                 btupdatepage(pagptr);
  1287.                 if (errstatus > 0) return;
  1288.             }
  1289.             else {
  1290.                 dk_dela(xpageref,k,&pagptr,&prpgref);
  1291.                 if (dk_pagetoosmall)
  1292.                     dk_underflow(prpgref,xpageref,(int) r);
  1293.                 if (errstatus > 0) return;
  1294.             }
  1295.         }
  1296.         else {
  1297.             dk_delb(xpageref);
  1298.             if (dk_pagetoosmall)
  1299.                 dk_underflow(prpgref,xpageref,(int) r);
  1300.             if (errstatus > 0) return;
  1301.         }
  1302.     }
  1303. }
  1304.  
  1305. void db_deletekey(indexfile *idxf, long *datarecnum, void *prockey)
  1306. {
  1307.     btpageptr pagptr;
  1308.  
  1309.     if (!vfyidxhdr(idxf)) return;
  1310.     dk_idxf = idxf;
  1311.     dk_datarecnum = datarecnum;
  1312.     dk_prockey = prockey;
  1313.     btxkey(prockey,idxf->keyl);
  1314.     ok = True;
  1315.     dk_delb(idxf->rr);
  1316.     if (errstatus > 0) return;
  1317.     if (dk_pagetoosmall) {
  1318.         btgetpage(idxf,idxf->rr,&pagptr);
  1319.         if (errstatus > 0) return;
  1320.         if (pagptr->itemsonpage == 0) {
  1321.             idxf->rr = pagptr->bckwpageref;
  1322.             btreturnpage(&pagptr);
  1323.             if (errstatus > 0) return;
  1324.         }
  1325.     }
  1326.     idxf->pp = 0;
  1327. }
  1328.  
  1329. void cleanup(void)
  1330. {
  1331.     if (shutdown != NULL) (*shutdown)();
  1332. }
  1333.  
  1334. bool io_error(int *loops, int wait, bool mustsucceed)
  1335. {
  1336.     uchar ch;
  1337.     bool abort,ioerr;
  1338.     word fatal;
  1339.     errorstring emsg;
  1340.  
  1341.     ioerr = (bool) (errstatus > 0);
  1342.     if (ioerr) {
  1343.         fatal = errstatus;
  1344.         abort = True;
  1345.         (*loops)--;
  1346.         if ((errstatus == RecLocked) && multiuser) {
  1347.             abort = False;
  1348.             if (wait > 0) delay(wait);
  1349.             if ((*loops == 0) && mustsucceed) {
  1350.                 gotoxy(1,1); clreol();
  1351.                 cwrite(LSC_UnexpectedLockedIndex);
  1352.                 do {
  1353.                     ch = getkey();
  1354.                     if ((ch >= 'a') && (ch <= 'z')) ch -= 'a'-'A';
  1355.                 } while (!((ch == _Retry) || (ch == _Abort)));
  1356.                 gotoxy(1,1);
  1357.                 clreol();
  1358.                 if (ch == _Retry)
  1359.                     *loops = idx_retries;
  1360.                 else
  1361.                     abort = True;
  1362.             }
  1363.         }
  1364.         if (*loops >= 0) resetstatus();
  1365.         if (abort) {
  1366.             if ((!recursive) && (shutdown != NULL)) {
  1367.                 recursive = True;
  1368.                 cleanup();
  1369.             }
  1370.             gotoxy(1,1); clreol();
  1371.             cwrite(LSC_FatalIO);
  1372.             sprintf(emsg,"%u",fatal);
  1373.             cwrite(emsg);
  1374.             gotoxy(1,2); clreol();
  1375.             cwrite(ioerrstr(emsg,fatal));
  1376.             gotoxy(1,3); clreol();
  1377.             cwrite(LSC_PressAnyKey);
  1378.             getkey();
  1379.             exit(0);
  1380.         }
  1381.     }
  1382.     return (ioerr);
  1383. }
  1384.  
  1385. void addkey(indexfile *idxf, long *datarecnum, void *prockey)
  1386. {
  1387.     _loop_count = idx_retries;
  1388.     do
  1389.         db_addkey(idxf,datarecnum,prockey);
  1390.     while (io_error(&_loop_count,0,True));
  1391.     if (ok && flush_if)
  1392.         flushindex(idxf);
  1393. }
  1394.  
  1395. void addrec(datafile *datf, long *r, void *buffer)
  1396. {
  1397.     _loop_count = retries;
  1398.     do
  1399.         db_addrec(datf,r,buffer);
  1400.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1401.     if (flush_df)
  1402.         flushfile(datf);
  1403. }
  1404.  
  1405. void clearkey(indexfile *idxf)
  1406. {
  1407.     db_clearkey(idxf);
  1408. }
  1409.  
  1410. void closefile(datafile *datf)
  1411. {
  1412.     _loop_count = retries;
  1413.     do
  1414.         db_closefile(datf);
  1415.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1416. }
  1417.  
  1418. void closeindex(indexfile *idxf)
  1419. {
  1420.     _loop_count = retries;
  1421.     do
  1422.         db_closeindex(idxf);
  1423.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1424. }
  1425.  
  1426. void deletekey(indexfile *idxf, long *datarecnum, void *prockey)
  1427. {
  1428.     _loop_count = idx_retries;
  1429.     do
  1430.         db_deletekey(idxf,datarecnum,prockey);
  1431.     while (io_error(&_loop_count,0,True));
  1432.     if (ok && flush_if)
  1433.         flushindex(idxf);
  1434. }
  1435.  
  1436. void deleterec(datafile *datf, long r)
  1437. {
  1438.     if (r==0) { btstatus = 2000;    btiocheck(datf,r); }
  1439.     _loop_count = retries;
  1440.     do
  1441.         db_deleterec(datf,r);
  1442.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1443.     if (flush_df)
  1444.         flushfile(datf);
  1445. }
  1446.  
  1447. void erasefile(datafile *datf)
  1448. {
  1449.     _loop_count = retries;
  1450.     do
  1451.         db_erasefile(datf);
  1452.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1453. }
  1454.  
  1455. void eraseindex(indexfile *idxf)
  1456. {
  1457.     _loop_count = retries;
  1458.     do
  1459.         db_eraseindex(idxf);
  1460.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1461. }
  1462.  
  1463. void flushfile(datafile *datf)
  1464. {
  1465.     _loop_count = retries;
  1466.     do
  1467.         db_flushfile(datf);
  1468.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1469. }
  1470.  
  1471. void flushindex(indexfile *idxf)
  1472. {
  1473.     _loop_count = retries;
  1474.     do
  1475.         db_flushindex(idxf);
  1476.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1477. }
  1478.  
  1479. long filelen(datafile *datf)
  1480. {
  1481.     long fl;
  1482.  
  1483.     _loop_count = retries;
  1484.     do
  1485.         fl = db_filelen(datf);
  1486.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1487.     return (fl);
  1488. }
  1489.  
  1490. void findkey(indexfile *idxf, long *datarecnum, void *prockey)
  1491. {
  1492.     _loop_count = idx_retries;
  1493.     do
  1494.         db_findkey(idxf,datarecnum,prockey);
  1495.     while (io_error(&_loop_count,0,True));
  1496. }
  1497.  
  1498. void getlockedrec(datafile *datf, long r, void *buffer)
  1499. {
  1500.     _loop_count = retries;
  1501.     do
  1502.         db_getlockedrec(datf,r,buffer);
  1503.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1504. }
  1505.  
  1506. void getrec(datafile *datf, long r, void *buffer)
  1507. {
  1508.     _loop_count = retries;
  1509.     do {
  1510.         db_getrec(datf,r,buffer);
  1511.         if (multiuser && (errstatus == RecLocked)) {
  1512.             resetstatus();
  1513.             db_getlockedrec(datf,r,buffer);
  1514.         }
  1515.         else
  1516.             lockget = False;
  1517.     } while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1518. }
  1519.  
  1520. void makefile(datafile *datf, strptr fname, word reclen)
  1521. {
  1522.     if (reclen > DB_mxdrs)
  1523.         reclen = DB_mxdrs;
  1524.     else
  1525.         if (reclen < DB_mdrs)
  1526.     reclen = DB_mdrs;
  1527.     _loop_count = retries;
  1528.     do
  1529.         db_makefile(datf,fname,reclen);
  1530.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1531. }
  1532.  
  1533. void makeindex(indexfile *idxf, strptr fname, byte keylen, byte s)
  1534. {
  1535.     if (keylen > DB_Klen)
  1536.         keylen = DB_Klen;
  1537.     _loop_count = retries;
  1538.     do
  1539.         db_makeindex(idxf,fname,keylen,s);
  1540.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1541. }
  1542.  
  1543. void nextkey(indexfile *idxf, long *datarecnum, void *prockey)
  1544. {
  1545.     _loop_count = idx_retries;
  1546.     do
  1547.         db_nextkey(idxf,datarecnum,prockey);
  1548.     while (io_error(&_loop_count,0,True));
  1549. }
  1550.  
  1551. void openfile(datafile *datf, strptr fname, word reclen)
  1552. {
  1553.     if (reclen > DB_mxdrs)
  1554.         reclen = DB_mxdrs;
  1555.     else
  1556.         if (reclen < DB_mdrs)
  1557.             reclen = DB_mdrs;
  1558.     _loop_count = retries;
  1559.     do
  1560.         db_openfile(datf,fname,reclen);
  1561.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1562. }
  1563.  
  1564. void openindex(indexfile *idxf, strptr fname, byte keylen, byte s)
  1565. {
  1566.     if (keylen > DB_Klen)
  1567.         keylen = DB_Klen;
  1568.     _loop_count = retries;
  1569.     do
  1570.         db_openindex(idxf,fname,keylen,s);
  1571.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1572. }
  1573.  
  1574. void prevkey(indexfile *idxf, long *datarecnum, void *prockey)
  1575. {
  1576.     _loop_count = idx_retries;
  1577.     do
  1578.         db_prevkey(idxf,datarecnum,prockey);
  1579.     while (io_error(&_loop_count,0,True));
  1580. }
  1581.  
  1582. void putrec(datafile *datf, long r, void *buffer)
  1583. {
  1584.     if (r==0) { btstatus = 2000;    btiocheck(datf,r); }
  1585.     _loop_count = retries;
  1586.     do
  1587.         db_putrec(datf,r,buffer);
  1588.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1589.     if (flush_df)
  1590.         flushfile(datf);
  1591. }
  1592.  
  1593. void searchkey(indexfile *idxf, long *datarecnum, void *prockey)
  1594. {
  1595.     _loop_count = idx_retries;
  1596.     do
  1597.         db_search(idxf,datarecnum,prockey);
  1598.     while (io_error(&_loop_count,0,True));
  1599. }
  1600.  
  1601. long usedrecs(datafile *datf)
  1602. {
  1603.     long ur;
  1604.  
  1605.     _loop_count = retries;
  1606.     do
  1607.         ur = db_usedrecs(datf);
  1608.     while (io_error(&_loop_count,0,True) && (_loop_count > 0));
  1609.     return (ur);
  1610. }
  1611.  
  1612. int lock_datf(datafile *datf, long rno, byte lck)
  1613. {
  1614.     int fval;
  1615.     splitlong start,range;
  1616.     union REGS regs;
  1617.  
  1618.     fval = 0;
  1619.     if (multiuser) {
  1620.         regs.h.ah = 0x5C;
  1621.         if (rno >= 0) {
  1622.             range.l = 4;
  1623.             start.l = rno * datf->itemsize;
  1624.         }
  1625.         else {
  1626.             range.l = datf->itemsize;
  1627.      start.l = 0;
  1628.             rno = 0;
  1629.         }
  1630.         regs.h.al = lck;
  1631.         regs.x.bx = datf->f.handle;
  1632.         regs.x.cx = start.w.h;
  1633.         regs.x.dx = start.w.l;
  1634.         regs.x.si = range.w.h;
  1635.         regs.x.di = range.w.l;
  1636.         intdos(®s,®s);
  1637.         if (regs.x.cflag)
  1638.             fval = regs.x.ax;
  1639.          if (fval == 1) fval = 0;
  1640.         else {
  1641.             if (lck == Lock) {
  1642.                 db_getrec(datf,rno,btrecbuf);
  1643.                 if (errstatus == 100) {
  1644.                     fval = lock_datf(datf,rno,UnLock);
  1645.                     fval = -1;
  1646.                     errstatus = 0;
  1647.                     btstatus = 0;
  1648.                 }
  1649.             }
  1650.         }
  1651.     }
  1652.     return (fval);
  1653. }
  1654.  
  1655. int lock_indexf(indexfile *indexf, long rno, byte lck)
  1656. {
  1657.     int fval;
  1658.  
  1659.     fval = 0;
  1660.     if (multiuser) {
  1661.         rno = -1;
  1662.         fval = lock_datf(&indexf->dataf,rno,lck);
  1663.     }
  1664.     return (fval);
  1665. }
  1666.  
  1667. void resetstatus(void)
  1668. {
  1669.     errstatus = 0;
  1670.     btstatus = 0;
  1671. }
  1672.  
  1673. void unit_initindex(void)
  1674. {
  1675.     int i;
  1676.  
  1677.     btrecbuf = (btrecordbufptr) db_malloc(sizeof(btrecordbuffer));
  1678.     btpagestk = (btpagestackptr) db_malloc(sizeof(btpagestack));
  1679.     btpgmap = (btpagemapptr) db_malloc(sizeof(btpagemap));
  1680.     memset(btpagestk,0,sizeof(btpagestack));
  1681.     for (i = 1 ; i <= DB_pstack ; i++)
  1682.         (*btpgmap)[i-1] = i;
  1683. }
  1684.  
  1685. void initindex(void)
  1686. {
  1687. }
  1688.  
  1689. /**********************  UNIT INITIALIZATION/EXIT CODE  *********************/
  1690.  
  1691. void db_tree_init(void)
  1692. {
  1693.     if (!initialized) {
  1694.         initialized = True;
  1695.         db_heap_init();
  1696.         db_key_init();
  1697.         ok = True;
  1698.         btstatus = 0;
  1699.         errstatus = 0;
  1700.         lockget = False;
  1701.         recursive = False;
  1702.         shutdown = NULL;
  1703.         retries = 0;
  1704.         idx_retries = 1000;
  1705.         unit_initindex();
  1706.     }
  1707. }
  1708.  
  1709. /****************************  END OF DB_TREE.C  ****************************/
  1710.